bitkeeper revision 1.1159.21.1 (41193c65K9NbWw4E7FhhvSPwFS3svQ)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 10 Aug 2004 21:21:41 +0000 (21:21 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 10 Aug 2004 21:21:41 +0000 (21:21 +0000)
More binary-rewrite patches.

linux-2.6.7-xen-sparse/arch/xen/i386/mm/fault.c
linux-2.6.7-xen-sparse/arch/xen/i386/mm/pgtable.c
linux-2.6.7-xen-sparse/arch/xen/kernel/fixup.c
linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/fixmap.h
linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/pgtable.h

index d850d279d5fea294f474b0ea33bb4cfc43967a20..f508ccd8c3e9b1e2d28a67686583654d06fd5887 100644 (file)
@@ -248,7 +248,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
         * (error_code & 4) == 0, and that the fault was not a
         * protection error (error_code & 1) == 0.
         */
-       if (unlikely(address >= TASK_SIZE)) { 
+       if (unlikely(address >= TASK_SIZE) ||
+           unlikely(address < (FIRST_USER_PGD_NR<<PGDIR_SHIFT))) { 
                if (!(error_code & 5))
                        goto vmalloc_fault;
                /* 
index cbab491f2eee3f3e97d584a6fb85b8f52fb029ee..b5fdd533a80b73f5412dfa4c0e90ec591f314a8e 100644 (file)
@@ -250,16 +250,21 @@ void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused)
        if (PTRS_PER_PMD == 1)
                spin_lock_irqsave(&pgd_lock, flags);
 
-       memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD,
-                       swapper_pg_dir + USER_PTRS_PER_PGD,
-                       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+       memcpy((pgd_t *)pgd,
+                       swapper_pg_dir,
+                       FIRST_USER_PGD_NR * sizeof(pgd_t));
+       memcpy((pgd_t *)pgd + FIRST_USER_PGD_NR + USER_PTRS_PER_PGD,
+                       swapper_pg_dir + FIRST_USER_PGD_NR + USER_PTRS_PER_PGD,
+                       (PTRS_PER_PGD - USER_PTRS_PER_PGD -
+                        FIRST_USER_PGD_NR) * sizeof(pgd_t));
 
        if (PTRS_PER_PMD > 1)
                goto out;
 
        pgd_list_add(pgd);
        spin_unlock_irqrestore(&pgd_lock, flags);
-       memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
+       memset((pgd_t *)pgd + FIRST_USER_PGD_NR,
+                       0, USER_PTRS_PER_PGD*sizeof(pgd_t));
  out:
        __make_page_readonly(pgd);
        queue_pgd_pin(__pa(pgd));
index 61c5497f400c08a17565b95108bffbef166ace5c..e20be71808f4d949bd5f6c94cb46c1e0bffe588e 100644 (file)
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/highmem.h>
+#include <linux/vmalloc.h>
 #include <asm/fixmap.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
-#if 0
+#if 1
 #define ASSERT(_p) \
     if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
     __LINE__, __FILE__); *(int*)0=0; }
 #define DPRINTK(_f, _a...) ((void)0)
 #endif
 
+static char            *fixup_buf;
+#define FIXUP_BUF_USER  PAGE_SIZE
+#define FIXUP_BUF_ORDER 1
+#define FIXUP_BUF_SIZE  (PAGE_SIZE<<FIXUP_BUF_ORDER)
+#define PATCH_LEN       5
+
 struct fixup_entry {
-    unsigned long  patch_addr;
+    unsigned long  patch_addr; /* XXX */
     unsigned char  patched_code[20];
     unsigned short patched_code_len;
     unsigned short fixup_idx;
+    unsigned short return_idx;
     struct fixup_entry *next;
 };
 
 #define FIXUP_HASHSZ 128
 static struct fixup_entry *fixup_hash[FIXUP_HASHSZ];
-#define FIXUP_HASH(_a) ((unsigned int)(_a) & (FIXUP_HASHSZ-1))
+static inline int FIXUP_HASH(char *b)
+{
+    int i, j = 0;
+    for ( i = 0; i < PATCH_LEN; i++ )
+        j ^= b[i];
+    return j & (FIXUP_HASHSZ-1);
+}
 
+/* General instruction properties. */
 #define INSN_SUFFIX_BYTES (7)
 #define PREFIX_BYTE       (1<<3)
 #define OPCODE_BYTE       (1<<4)  
 #define HAS_MODRM         (1<<5)
 
-#define X  0 /* invalid */
+/* Helpful codes for the main decode routine. */
+#define CODE_MASK         (3<<6)
+#define PUSH              (0<<6) /* PUSH onto stack */
+#define POP               (1<<6) /* POP from stack */
+#define JMP               (2<<6) /* 8-bit relative JMP */
+
+/* Short forms for the table. */
+#define X  0 /* invalid for some random reason */
+#define S  0 /* invalid because it munges the stack */
 #define P  PREFIX_BYTE
 #define O  OPCODE_BYTE
 #define M  HAS_MODRM
 
 static unsigned char insn_decode[256] = {
     /* 0x00 - 0x0F */
-    O|M, O|M, O|M, O|M, O|1, O|4, O, O,
-    O|M, O|M, O|M, O|M, O|1, O|4, O, X,
+    O|M, O|M, O|M, O|M, O|1, O|4, S, S,
+    O|M, O|M, O|M, O|M, O|1, O|4, S, X,
     /* 0x10 - 0x1F */
-    O|M, O|M, O|M, O|M, O|1, O|4, O, O,
-    O|M, O|M, O|M, O|M, O|1, O|4, O, O,
+    O|M, O|M, O|M, O|M, O|1, O|4, S, S,
+    O|M, O|M, O|M, O|M, O|1, O|4, S, S,
     /* 0x20 - 0x2F */
     O|M, O|M, O|M, O|M, O|1, O|4, P, O,
     O|M, O|M, O|M, O|M, O|1, O|4, P, O,
@@ -79,20 +102,20 @@ static unsigned char insn_decode[256] = {
     O|M, O|M, O|M, O|M, O|1, O|4, P, O,
     O|M, O|M, O|M, O|M, O|1, O|4, P, O,
     /* 0x40 - 0x4F */
-    O, O, O, O, O, O, O, O,
-    O, O, O, O, O, O, O, O,
+    O, O, O, O, S, O, O, O,
+    O, O, O, O, S, O, O, O,
     /* 0x50 - 0x5F */
-    O, O, O, O, O, O, O, O,
-    O, O, O, O, O, O, O, O,
+    O|PUSH, O|PUSH, O|PUSH, O|PUSH, S, O|PUSH, O|PUSH, O|PUSH,
+    O|POP, O|POP, O|POP, O|POP, S, O|POP, O|POP, O|POP,
     /* 0x60 - 0x6F */
-    O, O, O|M, O|M, P, P, X, X,
-    O|4, O|M|4, O|1, O|M|1, O, O, O, O,
+    S, S, O|M, O|M, P, P, X, X,
+    O|4|PUSH, O|M|4, O|1|PUSH, O|M|1, O, O, O, O,
     /* 0x70 - 0x7F */
-    O|1, O|1, O|1, O|1, O|1, O|1, O|1, O|1,
-    O|1, O|1, O|1, O|1, O|1, O|1, O|1, O|1,
+    O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP,
+    O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP,
     /* 0x80 - 0x8F */
     O|M|1, O|M|4, O|M|1, O|M|1, O|M, O|M, O|M, O|M,
-    O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M, 
+    O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M|POP
     /* 0x90 - 0x9F */
     O, O, O, O, O, O, O, O,
     O, O, X, O, O, O, O, O,
@@ -110,13 +133,15 @@ static unsigned char insn_decode[256] = {
     X, X, X, X, X, X, X, X,
     /* 0xE0 - 0xEF */
     X, X, X, X, X, X, X, X,
-    X, O|4, X, O|1, X, X, X, X,
+    X, O|4, X, O|1|JMP, X, X, X, X,
     /* 0xF0 - 0xFF */
     P, X, P, P, O, O, O|M|1, O|M|4, 
-    O, O, O, O, O, O, O|M, O|M
+    O, O, O, O, O, O, O|M, X
 };
 
-static unsigned int get_insn_len(unsigned char *insn, unsigned char *p_opcode)
+static unsigned int get_insn_len(unsigned char *insn, 
+                                 unsigned char *p_opcode,
+                                 unsigned char *p_decode)
 {
     unsigned char b, d, *pb, mod, rm;
 
@@ -130,10 +155,14 @@ static unsigned int get_insn_len(unsigned char *insn, unsigned char *p_opcode)
     }
 
     *p_opcode = b;
+    *p_decode = d;
 
     /* 2. Ensure we have a valid opcode byte. */
     if ( !(d & OPCODE_BYTE) )
+    {
+        printk(KERN_ALERT " *** %02x %02x %02x\n", pb[0], pb[1], pb[2]);
         return 0;
+    }
 
     /* 3. Process Mod/RM if there is one. */
     if ( d & HAS_MODRM )
@@ -175,13 +204,10 @@ static unsigned char handleable_code[32] = {
 asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
 {
     static unsigned int fixup_idx = 0;
-    int relbyte_idx = -1, relword_idx = -1, save_indirect_reg;
+    unsigned int fi;
+    int save_indirect_reg, hash, rel_idx;
     unsigned int insn_len = (unsigned int)error_code, new_insn_len;
-    unsigned char b[20], modrm, mod, reg, rm, patch[5], opcode;
-    unsigned char *fixup_buf = 
-        (unsigned char *)fix_to_virt(FIX_4GB_SEGMENT_FIXUP_RW);
-    unsigned long fixup_buf_user = 
-        fix_to_virt(FIX_4GB_SEGMENT_FIXUP_RO);
+    unsigned char b[20], modrm, mod, reg, rm, patch[PATCH_LEN], opcode, decode;
     unsigned long eip = regs->eip - insn_len;
     struct fixup_entry *fe;
     pte_t *pte;
@@ -198,28 +224,50 @@ asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
 
     if ( unlikely(eip >= (PAGE_OFFSET-32)) )
     {
-        if ( (eip < fixup_buf_user) || (eip >= (fixup_buf_user+PAGE_SIZE-32)) )
+        DPRINTK("User executing out of kernel space?!");
+        return;
+    }
+    
+    if ( unlikely(((eip ^ (eip+PATCH_LEN)) & PAGE_MASK) != 0) )
+    {
+        DPRINTK("Patch instruction would straddle a page boundary.");
+        return;
+    }
+
+    /*
+     * Check that the page to be patched is part of a read-only VMA. This 
+     * means that our patch will never erroneously get flushed to disc.
+     */
+    if ( eip > (FIXUP_BUF_USER + FIXUP_BUF_SIZE) ) /* don't check fixup area */
+    {
+        /* [SMP] Need to the mmap_sem semaphore. */
+        struct vm_area_struct *vma = find_vma(current->mm, eip);
+        if ( (vma == NULL) || (vma->vm_flags & VM_MAYSHARE) )
         {
-            DPRINTK("User executing out of kernel space?!");
+            DPRINTK("Cannot patch a shareable VMA.");
             return;
         }
-        /* We know it's safe to directly copy teh bytes into our buffer. */
-        memcpy(b, (void *)eip, sizeof(b));
     }
-    else if ( unlikely(copy_from_user(b, (void *)eip, sizeof(b)) != 0) )
+
+    if ( unlikely(copy_from_user(b, (void *)eip, sizeof(b)) != 0) )
     {
         DPRINTK("Could not read instruction bytes from user space.");
         return;
     }
 
-    if ( unlikely(((eip ^ (eip+5)) & PAGE_MASK) != 0) )
+    /* Already created a fixup for this address and code sequence? */
+    hash = FIXUP_HASH(b);
+    for ( fe = fixup_hash[hash];
+          fe != NULL; fe = fe->next )
     {
-        DPRINTK("Patch instruction would straddle a page boundary.");
-        return;
+        if ( eip != fe->patch_addr )
+            continue; /* XXX */
+        if ( memcmp(fe->patched_code, b, fe->patched_code_len) == 0 )
+            goto do_the_patch;
     }
 
     /* Guaranteed enough room to patch? */
-    if ( unlikely(fixup_idx > (PAGE_SIZE-32)) )
+    if ( unlikely((fi = fixup_idx) > (FIXUP_BUF_SIZE-32)) )
     {
         static int printed = 0;
         if ( !printed )
@@ -268,40 +316,77 @@ asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
         return;
     }
 
-    while ( insn_len < 5 )
+    /* Indirect jump pointer. */
+    *(u32 *)&fixup_buf[fi] = FIXUP_BUF_USER + fi + 4;
+    fi += 4;
+
+    /* push <r32> */
+    if ( save_indirect_reg )
+        fixup_buf[fi++] = 0x50 + rm;
+
+    /* add %gs:0,<r32> */
+    fixup_buf[fi++] = 0x65;
+    fixup_buf[fi++] = 0x03;
+    fixup_buf[fi++] = 0x05 | (rm << 3);
+    *(unsigned long *)&fixup_buf[fi] = 0;
+    fi += 4;
+
+    /* Relocate the faulting instruction, minus the GS override. */
+    memcpy(&fixup_buf[fi], &b[1], error_code - 1);
+    fi += error_code - 1;
+
+    /* pop <r32> */
+    if ( save_indirect_reg )
+        fixup_buf[fi++] = 0x58 + rm;
+
+    while ( insn_len < PATCH_LEN )
     {
         /* Bail if can't decode the following instruction. */
         if ( unlikely((new_insn_len =
-                       get_insn_len(&b[insn_len], &opcode)) == 0) )
+                       get_insn_len(&b[insn_len], &opcode, &decode)) == 0) )
         {
             DPRINTK("Could not decode following instruction.");
             return;
         }
 
         /* We track one 8-bit relative offset for patching later. */
-        if ( ((opcode >= 0x70) && (opcode <= 0x7f)) || (opcode == 0xeb) )
+        if ( (decode & CODE_MASK) == JMP )
         {
-            if ( relbyte_idx != -1 )
-            {
-                DPRINTK("Multiple relative offsets in patch seq!");
-                return;
-            }
-            relbyte_idx = insn_len;
-            while ( b[relbyte_idx] != opcode )
-                relbyte_idx++;
-            relbyte_idx++;
+            rel_idx = insn_len;
+            while ( (fixup_buf[fi++] = b[rel_idx++]) != opcode )
+                continue;
+            
+            /* Patch the 8-bit relative offset. */
+            int idx = fe->fixup_idx + relbyte_idx + 6 + 4/**/;
+            if ( save_indirect_reg )
+                idx += 2;
+            fixup_buf[idx] = fi - (idx + 1);
+        
+            /* jmp <rel32> */
+            fixup_buf[fi++] = 0xe9;
+            fi += 4;
+            *(unsigned long *)&fixup_buf[fi-4] = 
+                (eip + relbyte_idx + 1 + (long)(char)b[relbyte_idx]) - 
+                (FIXUP_BUF_USER + fi);
         }
         else if ( opcode == 0xe9 )
         {
-            if ( relword_idx != -1 )
-            {
-                DPRINTK("Multiple relative offsets in patch seq!");
-                return;
-            }
-            relword_idx = insn_len;
-            while ( b[relword_idx] != opcode )
-                relword_idx++;
-            relword_idx++;
+            rel_idx = insn_len;
+            while ( (fixup_buf[fi++] = b[rel_idx++]) != opcode )
+                continue;
+            
+            /* Patch the 32-bit relative offset. */
+            int idx = fe->fixup_idx + relword_idx + 6 + 4/**/;
+            if ( save_indirect_reg )
+                idx += 2;
+            *(unsigned long *)&fixup_buf[idx] +=
+                (eip + relword_idx) - (FIXUP_BUF_USER + idx);
+        }
+        else
+        {
+            /* Relocate the instruction verbatim. */
+            memcpy(&fixup_buf[fi], &b[insn_len], new_insn_len);
+            fi += new_insn_len;
         }
 
         if ( (insn_len += new_insn_len) > 20 )
@@ -311,7 +396,7 @@ asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
         }
 
         /* The instructions together must be no smaller than 'jmp <disp32>'. */
-        if ( insn_len >= 5 )
+        if ( insn_len >= PATCH_LEN )
             break;
 
         /* Can't have a RET in the middle of a patch sequence. */
@@ -322,120 +407,70 @@ asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
         }
     }
 
-    /* Already created a fixup for this address and code sequence? */
-    for ( fe = fixup_hash[FIXUP_HASH(eip)];
-          fe != NULL; fe = fe->next )
-    {
-        if ( (fe->patch_addr == eip) &&
-             (fe->patched_code_len == insn_len) &&
-             (memcmp(fe->patched_code, b, insn_len) == 0) )
-            goto do_the_patch;
-    }
-
-    /* No existing patch -- create an entry for one. */
+    /* Create an entry for a new fixup patch. */
     fe = kmalloc(sizeof(struct fixup_entry), GFP_KERNEL);
     if ( unlikely(fe == NULL) )
     {
         DPRINTK("Not enough memory to allocate a fixup_entry.");
         return;
     }
-    fe->patch_addr = eip;
+    fe->patch_addr = eip; /* XXX */
     fe->patched_code_len = insn_len;
     memcpy(fe->patched_code, b, insn_len);
     fe->fixup_idx = fixup_idx;
-    fe->next = fixup_hash[FIXUP_HASH(eip)];
-    fixup_hash[FIXUP_HASH(eip)] = fe;
-    
-    /* push <r32> */
-    if ( save_indirect_reg )
-        fixup_buf[fixup_idx++] = 0x50 + rm;
-
-    /* add %gs:0,<r32> */
-    fixup_buf[fixup_idx++] = 0x65;
-    fixup_buf[fixup_idx++] = 0x03;
-    fixup_buf[fixup_idx++] = 0x05 | (rm << 3);
-    *(unsigned long *)&fixup_buf[fixup_idx] = 0;
-    fixup_idx += 4;
+    fe->return_idx = 
+        fixup_idx + error_code + 6 + 4/**/ + (save_indirect_reg ? 2 : 0);
+    fe->next = fixup_hash[hash];
+    fixup_hash[hash] = fe;
 
-    /* First relocated instruction, minus the GS override. */
-    memcpy(&fixup_buf[fixup_idx], &b[1], error_code - 1);
-    fixup_idx += error_code - 1;
-
-    /* pop <r32> */
-    if ( save_indirect_reg )
-        fixup_buf[fixup_idx++] = 0x58 + rm;
-
-    if ( insn_len != error_code )
-    {
-        /* Relocated instructions. */
-        memcpy(&fixup_buf[fixup_idx], &b[error_code], insn_len - error_code);
-        fixup_idx += insn_len - error_code;
-    }
 
     /* jmp <rel32> */
-    fixup_buf[fixup_idx++] = 0xe9;
-    fixup_idx += 4;
-    *(unsigned long *)&fixup_buf[fixup_idx-4] = 
-        (eip + insn_len) - (fixup_buf_user + fixup_idx);
+    fixup_buf[fi++] = 0xe9;
+    fi += 4;
+    *(unsigned long *)&fixup_buf[fi-4] = 
+        (eip + insn_len) - (FIXUP_BUF_USER + fi);
 
-    if ( relbyte_idx != -1 )
-    {
-        /* Patch the 8-bit relative offset. */
-        int idx = fe->fixup_idx + relbyte_idx + 6;
-        if ( save_indirect_reg )
-            idx += 2;
-        fixup_buf[idx] = fixup_idx - (idx + 1);
-        
-        /* jmp <rel32> */
-        fixup_buf[fixup_idx++] = 0xe9;
-        fixup_idx += 4;
-        *(unsigned long *)&fixup_buf[fixup_idx-4] = 
-            (eip + relbyte_idx + 1 + (long)(char)b[relbyte_idx]) - 
-            (fixup_buf_user + fixup_idx);
-    }
-    else if ( relword_idx != -1 )
+    /* Commit the patch. */
+    fixup_idx = fi;
+
+#if 0
+    if ( fe->fixup_idx == 4122 )
     {
-        /* Patch the 32-bit relative offset by subtracting the code disp. */
-        int idx = fe->fixup_idx + relword_idx + 6;
-        if ( save_indirect_reg )
-            idx += 2;
-        *(unsigned long *)&fixup_buf[idx] +=
-            (eip + relword_idx) - (fixup_buf_user + idx);
+        int iii;
+        printk(KERN_ALERT "EIP == %08lx; USER_EIP == %08lx\n",
+               eip, FIXUP_BUF_USER + fe->fixup_idx);
+        printk(KERN_ALERT " .byte ");
+        for ( iii = 0; iii < insn_len; iii++ )
+            printk("0x%02x,", b[iii]);
+        printk("\n");
+        printk(KERN_ALERT " .byte ");
+        for ( iii = fe->fixup_idx; iii < fi; iii++ )
+            printk("0x%02x,", fixup_buf[iii]);
+        printk("\n");
+        printk(KERN_ALERT " .byte ");
+        for ( iii = fe->fixup_idx; iii < fi; iii++ )
+            printk("0x%02x,", ((char *)FIXUP_BUF_USER)[iii]);
+        printk("\n");
     }
+#endif
 
  do_the_patch:
     /* Create the patching instruction in a temporary buffer. */
-    patch[0] = 0xe9;
-    *(unsigned long *)&patch[1] = 
-        (fixup_buf_user + fe->fixup_idx) - (eip + 5);
-
-    /*
-     * Check that the page to be patched is part of a read-only VMA. This 
-     * means that our patch will never erroneously get flushed to disc.
-     */
-    if ( eip < PAGE_OFFSET ) /* don't need to check the fixmap area */
-    {
-        /* [SMP] Need to the mmap_sem semaphore. */
-        struct vm_area_struct *vma = find_vma(current->mm, eip);
-        if ( (vma == NULL) || (vma->vm_flags & VM_MAYSHARE) )
-        {
-            DPRINTK("Cannot patch a shareable VMA.");
-            return;
-        }
-    }
+    patch[0] = 0x67;
+    patch[1] = 0xff;
+    patch[2] = 0x26; /* call <r/m16> */
+    *(u16 *)&patch[3] = FIXUP_BUF_USER + fe->fixup_idx;
 
     /* [SMP] Need to pause other threads while patching. */
     pgd = pgd_offset(current->mm, eip);
     pmd = pmd_offset(pgd, eip);
     pte = pte_offset_kernel(pmd, eip);
     veip = kmap(pte_page(*pte));
-    memcpy((char *)veip + (eip & ~PAGE_MASK), patch, 5);
+    memcpy((char *)veip + (eip & ~PAGE_MASK), patch, PATCH_LEN);
     kunmap(pte_page(*pte));
 
     /* Success! Return to user land to execute 2nd insn of the pair. */
-    regs->eip = fixup_buf_user + fe->fixup_idx + error_code + 6;
-    if ( save_indirect_reg )
-        regs->eip += 2;
+    regs->eip = FIXUP_BUF_USER + fe->return_idx;
     return;
 }
 
@@ -443,7 +478,9 @@ static int nosegfixup = 0;
 
 static int __init fixup_init(void)
 {
-    unsigned long page;
+    struct vm_struct vma;
+    struct page *_pages[1<<FIXUP_BUF_ORDER], **pages=_pages;
+    int i;
 
     if ( nosegfixup )
         return 0;
@@ -451,9 +488,14 @@ static int __init fixup_init(void)
     HYPERVISOR_vm_assist(VMASST_CMD_enable,
                          VMASST_TYPE_4gb_segments_notify);
 
-    page = get_zeroed_page(GFP_ATOMIC);
-    __set_fixmap(FIX_4GB_SEGMENT_FIXUP_RO, __pa(page), PAGE_READONLY);
-    __set_fixmap(FIX_4GB_SEGMENT_FIXUP_RW, __pa(page), PAGE_KERNEL);
+    fixup_buf = (char *)__get_free_pages(GFP_ATOMIC, FIXUP_BUF_ORDER);
+    for ( i = 0; i < (1<<FIXUP_BUF_ORDER); i++ )
+        _pages[i] = virt_to_page(fixup_buf) + i;
+
+    vma.addr = (void *)FIXUP_BUF_USER;
+    vma.size = FIXUP_BUF_SIZE + PAGE_SIZE; /* fucking stupid interface */
+    if ( map_vm_area(&vma, PAGE_READONLY, &pages) != 0 )
+        BUG();
 
     memset(fixup_hash, 0, sizeof(fixup_hash));
 
index d4c105ea93a63052048ca92493f3fb9722b34eb3..0bfb839f2028dbb28e01c2d1cb1fd0fa857f3928 100644 (file)
@@ -44,8 +44,6 @@
 enum fixed_addresses {
        FIX_HOLE,
        FIX_VSYSCALL,
-       FIX_4GB_SEGMENT_FIXUP_RO,
-       FIX_4GB_SEGMENT_FIXUP_RW,
 #ifdef CONFIG_X86_LOCAL_APIC
        FIX_APIC_BASE,  /* local (CPU) APIC) -- required for SMP or not */
 #endif
@@ -128,8 +126,8 @@ extern void __set_fixmap_ma (enum fixed_addresses idx,
  * This is the range that is readable by user mode, and things
  * acting like user mode such as get_user_pages.
  */
-#define FIXADDR_USER_START     (__fix_to_virt(FIX_4GB_SEGMENT_FIXUP_RO))
-#define FIXADDR_USER_END       (FIXADDR_USER_START + (2*PAGE_SIZE))
+#define FIXADDR_USER_START     (__fix_to_virt(FIX_VSYSCALL))
+#define FIXADDR_USER_END       (FIXADDR_USER_START + PAGE_SIZE)
 
 
 extern void __this_fixmap_does_not_exist(void);
index be31d10f300157aac86fe0ac7e36abbc605a241b..8fd64dfae2e0da953c424f732291fd85b2b4e1d9 100644 (file)
@@ -64,16 +64,17 @@ void paging_init(void);
 #define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 
-#define USER_PTRS_PER_PGD      (TASK_SIZE/PGDIR_SIZE)
-#define FIRST_USER_PGD_NR      0
+#define FIRST_USER_PGD_NR      1
+#define USER_PTRS_PER_PGD      ((TASK_SIZE/PGDIR_SIZE) - FIRST_USER_PGD_NR)
 
+#if 0 /* XEN */
 #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
 #define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
 
 #define TWOLEVEL_PGDIR_SHIFT   22
 #define BOOT_USER_PGD_PTRS (__PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT)
 #define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS)
-
+#endif
 
 #ifndef __ASSEMBLY__
 /* Just any arbitrary offset to the start of the vmalloc VM area: the